package com.ycy.lucene.index;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.ycy.entity.ShopBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.BytesRef;
import org.wltea.analyzer.lucene.IKAnalyzer6x;

import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

@Slf4j
public class IndexCreateDemo {

  //源文件
  public static final File jsonfile;
  public static String indexpath;

  static {
    // 获取用户目录
    String userDirectory = System.getProperty("user.home");
    // 打印用户目录
    log.info("用户目录: " + userDirectory);
    // 获取文件分隔符
    String fileSeparator = System.getProperty("file.separator");
    // 打印文件分隔符
    log.info("文件分隔符: " + fileSeparator);

    String pathname = userDirectory + fileSeparator +"Desktop" + fileSeparator+ "linshilucenedata" + fileSeparator + "shop.json.txt";
    jsonfile = new File(pathname);
    indexpath = userDirectory + fileSeparator +"Desktop" + fileSeparator+ "linshilucenedata" + fileSeparator + "ix2";
    log.info("数据源目录 -> {} 索引生成目录 -> {}", pathname, indexpath);
  }

  Directory directory;

  private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");

  public IndexCreateDemo() {
  }

  public static void main(String[] args) {
    Path path = Paths.get(indexpath);
    Directory directory = null;
    try {
      directory = FSDirectory.open(path);
      IndexCreateDemo indexCreateDemo = new IndexCreateDemo();
      indexCreateDemo.createIndex();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  public void createIndex() {

    try {
      System.out.println("start create index ... ");
      Path path = Paths.get(indexpath);
      try {
        directory = FSDirectory.open(path);
      } catch (IOException e) {
        e.printStackTrace();
      }
      Analyzer standardAnalyzer = new IKAnalyzer6x();
//      Analyzer ik = new IKAnalyzer();
      //指定分词器
      IndexWriterConfig indexWriterConfig = new IndexWriterConfig(standardAnalyzer);
      indexWriterConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE);//覆盖索引
      IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
      //删除
//      indexWriter.deleteAll();
//      indexWriter.commit();

      JsonFactory jsonFactory = new JsonFactory();
      jsonFactory.enable(JsonParser.Feature.ALLOW_COMMENTS);
      ObjectMapper mapper = new ObjectMapper(jsonFactory);
      BufferedReader br = new BufferedReader(new InputStreamReader(
              this.getClass().getClassLoader().getResourceAsStream("shop.json.txt")));
      String line;
      List<String> shopEntityStr = Lists.newArrayList();
      int count = 0;

      List<Document> documents = Lists.newArrayList();

      while ((line = br.readLine()) != null) {
        count++;
        int group = count / 10;
        ShopBean shopBean = mapper.readValue(line, ShopBean.class);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(simpleDateFormat.parse("20190505"));
        calendar.set(Calendar.MONTH, -count);
        shopBean.openDate = simpleDateFormat.format(calendar.getTime());
        shopBean.shape = null;
        shopBean.sales = new Random().nextInt(100);
        shopBean.commentScore = new Random().nextFloat();
        shopEntityStr.add(JSONObject.toJSONString(shopBean));

        Document document = newDocument(shopBean, group);

        documents.add(document);
      }
      FileUtils.writeLines(jsonfile, Lists.newArrayList(shopEntityStr), false);

      for (Document document : documents) {
        indexWriter.addDocument(document);
      }
      indexWriter.commit();

//      List<Document> documents1 = documents.subList(0, 10);
//      for (Document document : documents1) {
//        //加权
//        indexWriter.addDocument(document);
//      }

      indexWriter.flush();
//      indexWriter.commit();

      //关闭的时候 自动 commit()
      indexWriter.close();
      System.out.println("end create index ... ");
    } catch (IOException | ParseException e) {
      e.printStackTrace();
    }
  }

  /**
   * http://www.codepub.cn/2016/05/20/Lucene-6-0-in-action-2-All-kinds-of-Field-and-sort-operations/
   * <p>
   * 在Lucene 6.0中，IntField替换为IntPoint，FloatField替换为FloatPoint，LongField替换为LongPoint，DoubleField替换为DoublePoint
   * <p>
   * <p>
   * 数值类型字段：“字段类型” 设置为：short、int、long、float、double的字段
   * <p>
   * 1、框架数值类型字段查询性能不太好，原因是设计时过多考虑节省空间，其实每个数值字段不过3-40MB；
   * 当前字段为 DocValuesField ，索引：DocValues
   * 查询：使用的是DocValuesNumericQuery，或者DocValuesRangeQuery；
   * <p>
   * 2、现改为IntField， LongField， FloatField ，DoubleField；
   * 字段为：NumericField ，索引：NumericType（用于查询）+ DocValues（用于排序、统计或兼容以前版本索引查询）
   * 查询：使用NumericRangeQuery
   *
   * @param shopBean
   * @param group
   * @return
   */
  private static Document newDocument(ShopBean shopBean, int group) {
    Document doc = new Document();

    // 存储
    doc.add( new TextField("id", String.valueOf(shopBean.id), Field.Store.YES));
    //对id排序,必需使用这个类
    doc.add(new NumericDocValuesField("id", shopBean.id));

//    TextField表示对name域值进行分词
    String name = shopBean.getName();
    //把值存起来
    TextField nameField = new TextField("name", name, Field.Store.YES);
    //不会把值存起来
//    TextField nameField = new TextField("name", name, Field.Store.NO);
    doc.add(nameField);

    //把值存起来
    TextField address = new TextField("address", shopBean.address == null ? "" : shopBean.address, Field.Store.YES);
    //不会把值存起来
//    TextField nameField = new TextField("name", name, Field.Store.NO);
    doc.add(address);

    long opendate = 0;
    try {
      opendate = simpleDateFormat.parse(shopBean.openDate).getTime();
    } catch (ParseException e) {
      e.printStackTrace();
    }
    //LongPoint只让字段支持范围查询,需要存储的话需要声明Stored, 使用KD-trees索引
      /*
      精确查询  Query query = IntPoint.newExactQuery("age", 11);
      范围查询  query = IntPoint.newRangeQuery("age", Math.addExact(11, 1), Math.addExact(22, -1));
      集合查询  IntPoint.newSetQuery("age", 11, 22, 33);
       */
    doc.add(new StoredField("opendate", opendate));
    doc.add(new LongPoint("opendate", opendate));

    //注意：NumericDocValuesField是用于排序 分组 分类 聚合
    doc.add(new NumericDocValuesField("opendate", opendate));

    doc.add(new StoredField("sales", shopBean.sales));
    doc.add(new NumericDocValuesField("sales", shopBean.sales)); //排序

    doc.add(new StoredField("commentscore", shopBean.commentScore));
    doc.add(new FloatPoint("commentscore", shopBean.commentScore)); //范围过滤

    doc.add(new StoredField("group", group));
    doc.add(new NumericDocValuesField("group", group));

    int i = new Random().nextInt(2);
    //加入一个has是否有库存
    doc.add(new StoredField("has", i));
    doc.add(new NumericDocValuesField("has", i));

    //多域值 可以用来排序
    char capacity = name.toCharArray()[0];
//    System.out.println(name + ":" + capacity + ":" + (int) capacity);
    doc.add(new SortedSetDocValuesField("sortByString", new BytesRef(capacity)));
    doc.add(new SortedSetDocValuesField("sortByString", new BytesRef(capacity)));
    doc.add(new SortedSetDocValuesField("sortByString", new BytesRef(capacity)));
    doc.add(new SortedSetDocValuesField("sortByString", new BytesRef(capacity)));

    //doc.add(new TextField("shape", shapeEnclosure, Field.Store.YES));
    // Potentially more than one shape in this field is supported by some
    // strategies; see the javadocs of the SpatialStrategy impl to see.
//    for (Shape shape : shapes) {
//      for (Field f : strategy.createIndexableFields(shape)) {
//        doc.add(f);
//      }
//      // store it too; the format is up to you
//      // (assume point in this example)
//      Point pt = (Point) shape;
//      doc.add(new StoredField(strategy.getFieldName(), pt.getX() + " " + pt.getY()));
//    }

    return doc;
  }

  public static String getContent(String bsolutePath) {
    String s = null;
    try {
      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(bsolutePath))));
      s = bufferedReader.readLine();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return s;
  }

  /**
   * 删除
   */
  public void delete() {

  }

  /**
   * 删除
   */
  public void deleteAll() {

  }

  /**
   * 恢复
   */
  public void undelete() {

  }

  /**
   * 没有更新,  实质上是删除之后在新增
   */
  public void update() {

  }

}
